
const Parse = require('parse/node');
const _=require('lodash');
const config=require("../config/config");
const template_file = config.template_file;
const UserObj = Parse.Object.extend("v5_user");
const ParseHelper = require('../helpers/parse');
const libCrypto=require('../lib/lib_crypto');
const ExcelService = require("./excel");
const axios = require('axios');

//在v5_user表中注册，然后在Parse中注册相同用户名用户并连接
//如果有错误会扔出错误
//isAdmin：true 注册为管理员
//isTeacher: true 注册为教师
async function reg(username,password,showName,isTeacher,isAdmin){
    //对密码加密
    const password_aes=libCrypto.aesEncrypt(password);
    const password_md5=libCrypto.md5WithSalt(password);
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(existParseUser){
        throw "用户已经存在";
    }
    //如果没有，保存新用户到v5_user表中
    var parseV5User =new UserObj({username,password_aes,password_md5,showName,isAdmin,isTeacher});
    const regUser = await parseV5User.save(null,{ useMasterKey: true }).then(ParseHelper.toJSON);
    //使用Parse注册同名用户
    const user = new Parse.User();
    user.set("username", username);
    user.set("password", password);
    await user.signUp();
    //连接到新用户到Parse用户系统
    const myAuthData = {
        id: username,  // Required field. Used to uniquely identify the linked account.
        password_md5
    };
    await user.linkWith('lims_auth', { authData: myAuthData });
    return regUser;
}

async function update_one_field(key,value,id){
    const parseUser= UserObj.createWithoutData(id);
    parseUser.set(key,value);
    return  parseUser.save(null,{ useMasterKey: true });
}

async function update(plainObject){
    const pObject = UserObj.createWithoutData(plainObject.objectId);
    const keys=Object.keys(plainObject).filter(k=>k!=="objectId"&& k!=="createdAt" && k!=="updatedAt"&& k!=="username"&& k!=="password_md5"&& k!=="password_aes");
    for(const k of keys){
        pObject.set(k,plainObject[k]);
    }
    return pObject.save(null,{ useMasterKey: true });
}

async function getUserInfo(username){
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    return await query.first({ useMasterKey: true });
}


//移除用户
async function remove(objectId){
    const query = new Parse.Query(UserObj);
    const v5user = await query.get(objectId,{useMasterKey: true });
    const jsonV5User = ParseHelper.toJSON(v5user);
    //删除User表中对应数据
    await v5user.destroy({ useMasterKey: true });
    //删除User表中对应数据
    const queryParseUser = new Parse.Query(Parse.User);
    queryParseUser.equalTo("username", jsonV5User.username);
    const deletedParseUser = await queryParseUser.first({ useMasterKey: true });
    await deletedParseUser.destroy({ useMasterKey: true });
}


//用v5_user表登录
//如果成功返回用户信息
//如果有错误会扔出错误
async function verifyByPasswordMD5(username,password_md5, unionid
){
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw "用户不存在";
    }
    if(existParseUser.get("password_md5")!==password_md5){
        throw "密码错误";
    }
    if(unionid){
        existParseUser.set('unionid',unionid)
    }
    return existParseUser.toJSON();
}

//第三方,如硬木盒子登录.使用密码明文
async function verifyByPassword(username,password){
    const password_md5=libCrypto.md5WithSalt(password);
    return verifyByPasswordMD5(username,password_md5);
}

//用v5_user表登录
//如果成功返回用户信息
//如果有错误会扔出错误
async function verifyByWechatAccessToken(username,access_token){
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw "用户不存在";
    }
    if(existParseUser.get("access_token")!==access_token){
        throw "密码错误";
    }
    return existParseUser.toJSON();
}


//用v5_user表登录
//如果成功返回用户信息
//如果有错误会扔出错误
async function verifyByXcxSessionKey(username,session_key){
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    console.log('session_key',session_key,ParseHelper.toJSON(existParseUser));
    if(!existParseUser){
        throw "用户不存在";
    }
    if(existParseUser.get("session_key")!==session_key){
        throw "密码错误";
    }
    return existParseUser.toJSON();
}


//修改密码
async function change_password(username,old_password,new_password){
    //对密码加密
    const old_password_aes=libCrypto.aesEncrypt(old_password);
    const old_password_md5=libCrypto.md5WithSalt(old_password);
    const new_password_aes=libCrypto.aesEncrypt(new_password);
    const new_password_md5=libCrypto.md5WithSalt(new_password);
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    query.equalTo('password_aes', old_password_aes);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw "用户不存在或原密码错误";
    }
    //设置新密码
    existParseUser.set("password_aes",new_password_aes);
    existParseUser.set("password_md5",new_password_md5);
    const result = await existParseUser.save(null,{ useMasterKey: true });

    try{
        //更新(删除后再加)Parse里的User表
        const queryParseUser = new Parse.Query(Parse.User);
        queryParseUser.equalTo('username', username);
        // const deletedParseUser = await queryParseUser.first({ useMasterKey: true });
        // await deletedParseUser.destroy({ useMasterKey: true });
        const deletedParseUsers = await queryParseUser.find({ useMasterKey: true });
        await Promise.all(deletedParseUsers.map(u=>u.destroy({ useMasterKey: true })));
        const user = new Parse.User();
        user.set("username", username);
        user.set("password", new_password);
        await user.signUp();
        const myAuthData = {
            id: username,  // Required field. Used to uniquely identify the linked account.
            password_md5:new_password_md5
        };
        await user.linkWith('lims_auth', { authData: myAuthData });
    }catch(ex){
        throw "密码修改失败:"+ex.message;
    }

    return result;
}

//重置密码，将密码设置为和username一样
async function reset_password(username){
    //对密码加密
    const new_password_aes=libCrypto.aesEncrypt(username);
    const new_password_md5=libCrypto.md5WithSalt(username);
    //查找表中是否已经有用户
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw "用户不存在";
    }

    //设置新密码
    existParseUser.set("password_aes",new_password_aes);
    existParseUser.set("password_md5",new_password_md5);
    await existParseUser.save(null,{ useMasterKey: true });

    try{
        //更新(删除后再加)Parse里的User表
        const queryParseUser = new Parse.Query(Parse.User);
        queryParseUser.equalTo('username', username);
        // const deletedParseUser = await queryParseUser.first({ useMasterKey: true });
        // await deletedParseUser.destroy({ useMasterKey: true });
        const deletedParseUsers = await queryParseUser.find({ useMasterKey: true });
        await Promise.all(deletedParseUsers.map(u=>u.destroy({ useMasterKey: true })));
        const user = new Parse.User();
        user.set("username", username);
        user.set("password", username);
        await user.signUp();
        const myAuthData = {
            id: username,  // Required field. Used to uniquely identify the linked account.
            password_md5:new_password_md5
        };
        await user.linkWith('lims_auth', { authData: myAuthData });
    }catch(ex){
        throw "密码重置失败:"+ex.message;
    }
}

//启动服务的时候新建用户admin
async function create_admin(){
    //查找表中是否已经有admin用户
    const query = new Parse.Query(UserObj);
    query.equalTo('username', 'admin');
    const existAdminParseUser= await query.first({ useMasterKey: true });
    if(!existAdminParseUser){
        return reg("admin","admin",'管理员',false,true);
    }
}
/*
usersData=[
    {
      "姓名": "dd",
      "学号": "ee",
      "班级": "ff"
    },
    {
      "姓名": "gg",
      "学号": "hh",
      "班级": "jj"
    }
  ]
fieldsMapping={
    "姓名":"showName",
    "学号":"username"
}
 */
//检查用户数据是否合规,有错误返回错误原因，
/*
result={
error:"错误原因", //无错误时无此项
exampleRows, //样例数据，前5行
mappedExampleRows, //对字段进行映射的样例数据
filePath, //文件路径
count //数据行数
}
 */
async function checkExcelFile(filePath,nameRowNumber,firstDataRowNumber,fieldsMapping){
    const usersData=await ExcelService.parseExcelFileFirstSheet(filePath,nameRowNumber,firstDataRowNumber);
    if(usersData.length>0){
        //取得前5行作为样例数据
        const exampleRows=_.take(usersData,5);
        var needDeleteExtra = false;
        if(template_file==='users_kmust.xlsx'||template_file==='users_seu.xlsx'){
            needDeleteExtra = true;
        }
        var mappedExampleRows=exampleRows.map(row=>mappingUserData(row,fieldsMapping,needDeleteExtra));
        if(template_file==='users_kmust.xlsx'||template_file==='users_seu.xlsx'){
            mappedExampleRows=mappedExampleRows.map(u=>addUsername(u));
        }
        const result={
            exampleRows,
            mappedExampleRows,
            filePath,
            count:usersData.length
        };
        if(!mappedExampleRows[0].hasOwnProperty("username")){
            result.error= "缺少用户名字段"
        }
        return result;
    }else{
        return {error:'文件内容为空'};
    }
}

/*
userData=
    {
        "姓名": "dd",
        "学号": "ee",
        "班级": "ff"
    }

fieldsMapping={
    "姓名":"showName",
    "学号":"username"
}
输出：

    {
        "showName": "dd",
        "username": "ee",
        "班级": "ff"
    }

*/
//根据fieldsMapping修改userData中的key
function mappingUserData(userData, fieldsMapping,needDeleteExtra=false){
    const mappedUserData={...userData};//复制要处理的数据
    Object.keys(mappedUserData).forEach(function(key) {
        const dbFieldName=fieldsMapping[key];
        if(dbFieldName){
            mappedUserData[dbFieldName] = mappedUserData[key];
            delete mappedUserData[key];
        }else{
           if(needDeleteExtra===true){
               delete mappedUserData[key];
           }
        }
    });
    return mappedUserData;
}

//补充密码字段:如果用户没有密码，以用户名作为密码
function addPassword(user){
    user["username"]=user.username.toString();
    user["showName"]=user.showName.toString();
    if(user.class_name){
        user["class_name"]=user.class_name.toString();
    }
    if(!user.hasOwnProperty("password")){
        user["password"]=user.username;
    }
    return user;
}

function addUsername(user){
    if(!user.hasOwnProperty("username")&&user.hasOwnProperty("studentNumber")){
        user["username"]=user.studentNumber;
    }
    return user;
}


//批量注册用户
/**
 * users=[{
        "username": "dd",
        "password": "ee",
        "班级": "ff"
    }]
 */
async function _batchRegUsers(users){
/*
对于曾经注册又标记为删除的用户，删除成为未注册用户
对于未注册用户，进行注册
在结果中反馈新增注册多少人
 */
    const usernames=users.map(u=>u.username);
    //删除这批用户中已经被标记为删除的用户
    await _removeDeletedUsers(usernames);
    const regUsers=await _queryRegUsers(usernames);
    const regUsernames=regUsers.map(u => u.get("username"));
    const unRegUsers=users.filter(u=>regUsernames.indexOf(u.username)<0);
    console.debug("unRegUsers",unRegUsers);
    //批量注册
    for (const u of unRegUsers){
        await reg(u.username,u.password)
    }
    return {regUsersCount:unRegUsers.length} //返回注册成功的人数

}

async function batchUpdateUsers(users){
    //批量更新用户数据
    const usernames=users.map(u=>u.username);
    //查询已经注册的用户
    const regUsers2=await _queryRegUsers(usernames);
    //为方便取得user，构造用户字典，以用户名为索引
    const usersDict={};//为方便取得user，构造用户字典，以用户名为索引
    users.forEach(u=>{
        const username=u.username;
        //username字段不用重复更新
        delete u.username;
        //如果有别的字段要更新，加入字典中
        if(Object.keys(u).length>0){
            usersDict[username]=u
        }
    });
    const dbUsersForUpdate=regUsers2.map(u=>{
        const userData=usersDict[u.get("username")];
        console.log('userData',userData);
        if(userData){
            //如果有用户数据，则准备更新
            return u.save(userData,{ useMasterKey: true });
        }else{
            //如果没有数据，返回null，下一步过滤掉
            return null;
        }
    }).filter(p=>(null!==p));//过滤掉为null的数据
    console.log("dbUsersForUpdate:",dbUsersForUpdate.length);
    await Parse.Object.saveAll(dbUsersForUpdate,{ useMasterKey: true });
    return {updateUsersCount:dbUsersForUpdate.length}
}

//删除v5_user表中标记为isDeleted的用户，包括Parse User表中的对应用户
async function _removeDeletedUsers(usernames){
    const query = new Parse.Query(UserObj);
    query.containedIn('username', usernames);
    query.equalTo("isDeleted",true);
    const deletedUsers= await query.find({ useMasterKey: true });
    const deletedUserNames=deletedUsers.map(u=>u.get("username"));
    console.debug('删除用户',deletedUserNames);
    //从v5_user表中删除用户
    await Promise.all(deletedUsers.map(u=>u.destroy({ useMasterKey: true })));
    //查找Parse User表并删除用户
    const queryParseUser = new Parse.Query(Parse.User);
    queryParseUser.containedIn("username", deletedUserNames);
    const deletedParseUsers = await queryParseUser.find({ useMasterKey: true });
    await Promise.all(deletedParseUsers.map(u=>u.destroy({ useMasterKey: true })));
}

//查询已注册用户,返回数组[user1,user2,...]
async function _queryRegUsers(usernames){
    const query = new Parse.Query(UserObj);
    query.containedIn('username', usernames);
    query.limit(999)
    return await query.find({ useMasterKey: true });
}


async function importExcelFile(filePath,nameRowNumber,firstDataRowNumber,fieldsMapping){
    const usersData=await ExcelService.parseExcelFileFirstSheet(filePath,nameRowNumber,firstDataRowNumber);
    var needDeleteExtra = false;
    if(template_file==='users_kmust.xlsx'||template_file==='users_seu.xlsx'){
        needDeleteExtra = true;
    }
    var mappedUsersData=usersData.map(ud=>mappingUserData(ud,fieldsMapping,needDeleteExtra));
    if(template_file==='users_kmust.xlsx'||template_file==='users_seu.xlsx'){
        mappedUsersData=mappedUsersData.map(u=>addUsername(u));
    }
    return _importUsersData(mappedUsersData);
}

async function _importUsersData(usersData){
    //为用户数据补全password字段
    const usersDataWithPassword=usersData.map(u=>addPassword(u));
    //批量注册
    const resultReg=await _batchRegUsers(usersDataWithPassword);
    //删除用户的敏感字段，为更新做准备
    const tidyUsers=usersData.map(u=>{
        delete u["password"];
        delete u["password_aes"];
        delete u["password_md5"];
        delete u["isAdmin"];
        delete u["isTeacher"];
        return u;
    });
    //批量更新用户数据
    await batchUpdateUsers(tidyUsers);
    return resultReg;
}

async function get_username_by_unionid(unionid){
    const query = new Parse.Query(UserObj);
    query.equalTo('unionid', unionid);
    const existParseUser= await query.first({ useMasterKey: true });
    if(existParseUser){
        return existParseUser.get("username");
    }else{
        return null;
    }
}
async function get_user_by_unionid(unionid){
    const query = new Parse.Query(UserObj);
    query.equalTo('unionid', unionid);
    return  await query.first({ useMasterKey: true }).then(ParseHelper.toJSON);
}

async function update_unionid_and_access_token(username,unionid,access_token){
    const query = new Parse.Query(UserObj);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw new Error("user not exist")
    }
    existParseUser.set("unionid",unionid);
    existParseUser.set("access_token",access_token);
    await  existParseUser.save(null,{ useMasterKey: true });
    return existParseUser.toJSON();
}

async function update_session_key_by_unionid(session_key,unionid){
    const query = new Parse.Query(UserObj);
    query.equalTo('unionid', unionid);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw new Error("user not exist")
    }
    existParseUser.set("session_key",session_key);
    await  existParseUser.save(null,{ useMasterKey: true });
    return existParseUser.toJSON();
}

async function link_user_and_wechat(username,unionid,access_token){
    //连接到新用户到Parse用户系统
    //连接本系统的用户名与微信的unionid
    const myAuthData = {
        id: unionid,  // Required field. Used to uniquely identify the linked account.
        access_token
    };
    const query = new Parse.Query(Parse.User);
    query.equalTo("username",username);
    const existParseUser= await query.first({ useMasterKey: true });
    console.log('existParseUser',existParseUser)
    if(existParseUser){
        return await existParseUser.linkWith('wechat_auth', { authData: myAuthData },{ useMasterKey: true });
    }else{
        const parseUser = new Parse.User({username});
        return await  parseUser.linkWith('wechat_auth', { authData: myAuthData },{ useMasterKey: true });
    }
}

async function unlink_user_and_wechat(username){
    //连接到新用户到Parse用户系统
    //解除连接本系统的用户名与微信的unionid
    const query = new Parse.Query(Parse.User);
    query.equalTo("username",username);
    const existParseUser= await query.first({ useMasterKey: true });
    await existParseUser._unlinkFrom('wechat_auth', { useMasterKey: true });
}

async function update_access_token(username,access_token){
    const query = new Parse.Query(UserObj);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw new Error("user not exist")
    }
    existParseUser.set("access_token",access_token);
    await  existParseUser.save(null,{ useMasterKey: true });
    return existParseUser.toJSON();
}

async function update_session_key(username,session_key){
    const query = new Parse.Query(UserObj);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        throw new Error("user not exist")
    }
    existParseUser.set("session_key",session_key);
    await  existParseUser.save(null,{ useMasterKey: true });
    return existParseUser.toJSON();
}


async function update_unionid(username,unionid){
    const query = new Parse.Query(UserObj);
    query.equalTo('username', username);
    const existParseUser= await query.first({ useMasterKey: true });
    if(!existParseUser){
        return {status: "fail", err: "用户名不存在"}
    }
    existParseUser.set("unionid",unionid);
    await  existParseUser.save(null,{ useMasterKey: true });
    return existParseUser.toJSON();
}

async function getStudents(value,key){
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.notEqualTo('isAdmin', true);
    query.notEqualTo('isTeacher', true);
    query.equalTo(key, value);
    query.select('username','showName','className');
    return await query.find({ useMasterKey: true });
}

//根据cardId找到用户
function getUserByCardId(cardId){
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('cardId', cardId);
    // query.select("username", "showName",'role');
    return query.first({ useMasterKey: true });
}

//根据用户名找到用户
function getUserByUserName(username) {
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('username', username);
    return query.first({ useMasterKey: true });
}

//根据用户名部分模糊查找用户
function queryUsersByUsername(partOfUsername) {
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDelete', true);
    query.contains('username', partOfUsername);
    query.select("username", "showName");
    query.limit(9999)
    return query.find({ useMasterKey: true }).then(ParseHelper.toJSONList);
}

//用户绑卡
function bindCard(userId, cardId){
    const user = UserObj.createWithoutData(userId);
    user.set("cardId", cardId);
    return user.save();
}


//如果用户名不是学号，根据user_number查找到学生
function getUserByUserNumber(user_number) {
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('number', user_number);
    return query.first({ useMasterKey: true });
}
//根据一组用户名查询一组用户
function getUsersByUsernames(usernames) {
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.containedIn('username', usernames);
    query.limit(9999);
    return  query.find({ useMasterKey: true });
}
//根据一组用户名查询一组用户
function getUserByShowName(showName) {
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.equalTo('showName', showName);
    return  query.first({ useMasterKey: true });
}

async function getAllClass(){
    const query = new Parse.Query(UserObj);
    query.limit(99999);
    query.notEqualTo("isDeleted", true);
    query.notEqualTo('isAdmin', true);
    query.notEqualTo('isTeacher', true);
    const pipeline = [
        {group: {objectId: '$class_name'}}
    ];
    const results = await query.aggregate(pipeline,{ useMasterKey: true });
    return results.map(r => r.objectId);
}

async function getClassStudents(class_name){
    const query = new Parse.Query(UserObj);
    query.notEqualTo('isDeleted', true);
    query.notEqualTo('isAdmin', true);
    query.notEqualTo('isTeacher', true);
    query.equalTo('class_name', class_name);
    query.select('username','showName','studentNumber');
    return await query.find({ useMasterKey: true });
}

async function getNonStudentList(){
    const teacherQuery = new Parse.Query(UserObj);
    teacherQuery.equalTo('isTeacher', true);

    const adminQuery = new Parse.Query(UserObj);
    adminQuery.equalTo('isAdmin', true);

    const query = Parse.Query.or(adminQuery, teacherQuery);
    query.notEqualTo('isDeleted', true);
    query.select('username','showName','isTeacher','isAdmin');
    return await query.find({ useMasterKey: true });
}

async function getTeachers(){
    const query = new Parse.Query(UserObj);
    query.equalTo('isTeacher', true);
    query.notEqualTo('isDeleted', true);
    query.select('username','showName');
    return await query.find({ useMasterKey: true });
}

async function unbindSupport(unionid){
    return  axios.post(`${config.supportUrl}/wechat/unbind`,{unionid});
}

module.exports={
    reg,
    verifyByPasswordMD5,
    verifyByPassword,
    verifyByWechatAccessToken,
    verifyByXcxSessionKey,
    change_password,
    reset_password,
    create_admin,
    checkExcelFile,
    importExcelFile,
    _removeDeletedUsers,
    _queryRegUsers,
    _batchRegUsers,
    batchUpdateUsers,
    _importUsersData,
    update_one_field,
    update,
    remove,
    getUserInfo,
    get_username_by_unionid,
    get_user_by_unionid,
    update_unionid,
    update_unionid_and_access_token,
    update_session_key_by_unionid,
    update_access_token,
    link_user_and_wechat,
    unlink_user_and_wechat,
    getStudents,
    getUserByCardId,
    getUserByUserName,
    getUserByUserNumber,
    getUsersByUsernames,
    getUserByShowName,
    getAllClass,
    getClassStudents,
    getNonStudentList,
    queryUsersByUsername,
    bindCard,
    getTeachers,
    update_session_key,
    unbindSupport
};